package math;


public class Add implements ArithmeticExpression {

  private ArithmeticExpression addend1;

  private ArithmeticExpression addend2;

  private Add(ArithmeticExpression addend1, ArithmeticExpression addend2) {
    this.addend1 = addend1;
    this.addend2 = addend2;
  }

  public static ArithmeticExpression createAdd(ArithmeticExpression addend1,
      ArithmeticExpression addend2) {
    return new Add(addend1, addend2);
  }

  @Override
  public ArithmeticExpression derivate(Variable var) {
    return Add.createAdd(addend1.derivate(var), addend2.derivate(var));
  }

  @Override
  public int getPriority() {
    return 5;
  }

  @Override
  public boolean isOne() {
    return false;
  }

  @Override
  public boolean isZero() {
    return addend1.isZero() && addend2.isZero();
  }

  @Override
  public ArithmeticExpression simplify() {
    return this;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    if (addend1.getPriority() > getPriority())
      sb.append('(');
    sb.append(addend1.toString());
    if (addend1.getPriority() > getPriority())
      sb.append(')');
    sb.append("+");
    if (addend2.getPriority() > getPriority())
      sb.append('(');
    sb.append(addend2.toString());
    if (addend2.getPriority() > getPriority())
      sb.append(')');
    return sb.toString();
  }

  public ArithmeticExpression getAddend1() {
    return addend1;
  }

  public ArithmeticExpression getAddend2() {
    return addend2;
  }

  @Override
  public boolean matches(Expression expr) {
    if (expr instanceof Add) {
      Add eAdd = (Add) expr;
      return addend1.matches(eAdd.getAddend1()) && addend2.matches(eAdd.getAddend2());
    } else
      return false;
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Add) {
      Add add2 = (Add) obj;
      return add2.addend1.equals(addend1) && add2.addend2.equals(addend2);
    } else
      return false;
  }

  @Override
  public int hashCode() {
    return addend1.hashCode() + (addend2.hashCode() ^ 7388127);
  }

  @Override
  public int countMembers() {
    return 1 + addend1.countMembers() + addend2.countMembers();
  }

  @Override
  public <R> R accept(ExpressionVisitor<R> visitor) {
    return visitor.visitAdd(this);
  }

}